<?php
/**
 * ============================================================================
 * 利用session的单例模型购物车
 * 1、将购物车理看做一个二维数组，键为商品主键，该类即操作该数组
 * 2、将该类中的实例保存在session中，即实现全局操作
 * ============================================================================
 * $Author: MrGeek 2018-08-12
 */
namespace lib;
use think\Session;
use think\Cookie;
use think\Db;
class Cart{
	private static $ins=null;
	private $items =[];
	final protected function __construct(){}
	final protected function __clone(){}
	protected static function getIns(){
		if(!(self::$ins instanceof self)){
			self::$ins =new self();
		}
		return self::$ins;
	}
	public static function getCart(){
		$sid=Cookie::get('uid','wechat');
		$sid=md5($sid);
		Session::init(['id' => $sid,'path'=>APP_PATH.'/web/session/']);
		if(!Session::has('cart','wechat') || !(Session::get('cart','wechat') instanceof self)){
			Session::set('cart',self::getIns(),'wechat');
		}
		return Session::get('cart','wechat');
	}
	/**
	 * 判断某商品是否存在
	 * @param $id  商品主键
	 */
	protected function hasItem($id){
		return array_key_exists($id,$this->items);
	}
	/**
	 * 添加商品
	 * @param $id   商品主键
	 * @param $num  添加数量
	 * @return 返回该商品数据
	 */
	public function addItem($param){
		$id =$param['id'];
		$num=!empty($param['num']) ? $param['num'] : 1;
		
		if($this->hasItem($id)){
			return $this->editNum($param);
		}else{
			$goods=Db::name('goods')->field('goods_id as id,goods_name,img,price,postage')->where('goods_id',$id)->find();
			if(!$goods) return rel(-1,'该商品不存在',[]);
			
			$goods['_num']=$num;
			$this->items[$id]=$goods;
			return $this->item($param);
		}
	}
	/**
	 * 修改商品数量
	 * @param $id    商品主键
	 * @param $num   需修改数量，若为负数且正好等于商品数量，则删除该商品
	 * @return 返回修改后的商品信息
	 */
	public function editNum($param){
		$id =$param['id'];
		$num=!empty($param['num']) ? $param['num'] : 1;
		
		if(!($this->hasItem($id))) 	return rel(-1,'该商品不存在于购物车',[]);
		
		$item=$this->items[$id];
		$_num=$item['_num']+$num;
		if($_num<0){
			return rel(-1,'减少数量不能大于当前数量',[]);
		}elseif($_num==0){
			return $this->delItem($param);
		}else{
			$this->items[$id]['_num']=$_num;
			return $this->item($param);
		}
	}
	/**
	 * 设置商品数量
	 * @param $id   商品数量
	 * @param $num	数量直接修改成多少。若为0则删除该商品
	 * @return 返回该商品信息
	 */
	public function setNum($param){
		$id =$param['id'];
		$num=$param['num'];
		 
		if($num<0) return rel(-1,'设置数量不能小于0',[]);
		if(!($this->hasItem($id))){					//如果不存在，则新增
			return $this->addItem($param);
		}else{
			if($num==0){
				return $this->delItem($param);
			}else{
				$this->items[$id]['_num']=$num;
				return $this->item($param);
			}
		}
	}
	/**
	 * 删除一个商品
	 */
	public function delItem($param){
		$id=$param['id'];
		unset($this->items[$id]);
		return rel(2,'删除该商品成功',[]);
	}
	/**
	 * 获取购物车内单个商品信息，包括总金额和总数量
	 */
	public function item($param){
	 	$id=$param['id'];
	 	if(!($this->hasItem($id))) 	return rel(-1,'该商品不存在',[]);
		
		$item=$this->items[$id];
		$item['total_price']=$item['price']*$item['_num'];
		return rel(1,'获取单个商品信息成功',$item);
	}
	/**
	 * 取出商品数组中的商品信息
	 * ids	商品主键数组
	 * type 是否删除，默认删除
	 */
	public function items($ids,$type=1){
		$rel=[];
		$num=0;
		$price=0;
		foreach($ids as $id){
			if(!empty($this->items[$id])){
				$rel[$id]=$this->items[$id]['_num'];
				if($type) unset($this->items[$id]);	
			}
		}
		return $rel;
//		return ['num'=>$num,'price'=>$price,'items'=>$rel];
	}
	/**
	 * 获取商品种类
	 */
	public function cate(){
		return rel(1,'获取购物车种类成功',count($this->items));
	}
	/**
	 * 获取购物车总数量
	 */
	public function num(){
		if(!$this->items){
			$rel=0;
		}else{
			$num=0;
			$items=$this->items;
			array_walk($items,function($v) use (&$num){
				$num+=$v['_num'];
			});
			$rel=$num;		
		}
		return rel(1,'获取购物车商品总数量成功',$rel);
	}
	/**
	 * 获取购物车内商品总金额
	 */
	public function price(){
		if(!$this->items){
			$rel=0;
		}else{
			$items=$this->items;
			$total_price=0;
			array_walk($items,function($v) use (&$total_price){
				$_price=$v['price']*$v['_num'];
				$total_price+=$_price;
			});
			$rel=$total_price;
		}
		return rel(1,'获取购物车商品总价成功',$rel);
	}
	/**
	 * 返回购物车数据
	 */
	public function cart(){
		if(!$this->items){
			$rel=[];
		}else{
			$items=$this->items;
			$total_price=0;
			$total_num=0;
			$postage=0;
			array_walk($items,function(&$v) use (&$total_num,&$total_price,&$postage){
				$_price=$v['price']*$v['_num'];
				$v['total_price']=$_price;
				$total_price+=$_price;
				$total_num+=$v['_num'];
				$postage+=$v['postage']*$v['_num'];
			});
			$rel=['total_price'=>$total_price,'total_num'=>$total_num,'postage'=>$postage,'cart'=>$items];
		}
		if(empty($rel['cart'])){
			return rel(-1,'购物车数据为空');
		}else{
			return rel(1,'获取购物车信息成功',$rel);	
		}
	}
	//清空购物车
	public function clear(){
		$this->items=[];
		return rel(1,'清空购物车成功',[]);
	}
}
